﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ApplicationOne
{
    public class ForwardList<T> : ICollection<T>
    {
        #region Inre klassen Node<T>
        /// <summary>
        /// Noden i ForwardList
        /// </summary>
        /// <typeparam name="T">Godtycklig värde- eller referenstyp</typeparam>
        private class Node<T>
        {
            public T value = default(T); //T kan vara antingen värde- eller referenstyp
            public Node<T> next = null;

            public Node()
            {
                
            }

            public Node(T value)
            {
                this.value = value;
            }

            ~Node()
            {
                Console.WriteLine("Node<T> destructor");
            }

        }
        #endregion

        private Node<T> head = null;

        #region Metoder

        public bool IsEmpty()
        {
            return head == null;
        }

        public void PushFront(T v)
        {
            Node<T> n = new Node<T>(v);
            n.next = head;
            head = n;
        }

        public T PopFront()
        {
            if (head == null)
                throw new Exception("ForwardList.Pop: Empty list");

            Node<T> n = head;
            head = head.next;
            return n.value;
        }

        public T Front()
        {
            if (head == null)
                throw new Exception("ForwardList.Front: Empty list");

            return head.value;
        }

        
        #endregion

        #region ICollection
        public void Add(T item)
        {
            PushFront(item);
        }

        public void Clear()
        {
            head = null;
        }

        public bool Contains(T item)
        {
            foreach (var v in this) //Kräver att GetEnumerator är implementerad
            {
                if (item.Equals(v))
                    return true;
            }

            return false;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get
            {
                Node<T> n = head;
                int s = 0;
                while (n != null)
                {
                    n = n.next;
                    s++;
                }
                return s;
            }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(T item)
        {
            //Referenstyp -> en unik item (referensvariabel) finns
            //Värdetyp  -> flera noder med värdet item kan finnas
            
            if (head == null)
                return false;

            if (item.Equals(head.value))
            {
                head = head.next;
                return true;
            }

            Node<T> nbefore = head;
            Node<T> n = head.next;

            while (n != null)
            {
                if (item.Equals(n.value))
                {
                    nbefore.next = n.next;
                    return true;
                }

                nbefore = n;
                n = n.next;
            }

            return false;
        }

        public IEnumerator<T> GetEnumerator()
        {
            Node<T> n = head;

            while (n != null)
            {
                yield return n.value;
                n = n.next;
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        } 
        #endregion
    }
}
